home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / Text / Show / Less / less-252 / lsystem.c < prev    next >
C/C++ Source or Header  |  1994-10-15  |  6KB  |  312 lines

  1. /*
  2.  * Copyright (c) 1984,1985,1989,1994  Mark Nudelman
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice in the documentation and/or other materials provided with 
  12.  *    the distribution.
  13.  *
  14.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
  15.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  17.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
  18.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  19.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
  20.  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
  21.  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
  22.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
  23.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 
  24.  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25.  */
  26.  
  27.  
  28. /*
  29.  * Routines to execute other programs.
  30.  * Necessarily very OS dependent.
  31.  */
  32.  
  33. #include <signal.h>
  34. #include "less.h"
  35. #include "position.h"
  36.  
  37. #if HAVE_FCNTL_H
  38. #include <fcntl.h>
  39. #endif
  40. #if MSOFTC
  41. #include <dos.h>
  42. #endif
  43.  
  44. extern int screen_trashed;
  45. extern IFILE curr_ifile;
  46.  
  47.  
  48. #if HAVE_SYSTEM
  49.  
  50. /*
  51.  * Pass the specified command to a shell to be executed.
  52.  * Like plain "system()", but handles resetting terminal modes, etc.
  53.  */
  54.     public void
  55. lsystem(cmd)
  56.     char *cmd;
  57. {
  58.     register int inp;
  59. #if MSOFTC
  60.     register int inp2;
  61. #endif
  62.     register char *shell;
  63.     register char *p;
  64.     IFILE save_ifile;
  65.  
  66.     /*
  67.      * Print the command which is to be executed,
  68.      * unless the command starts with a "-".
  69.      */
  70.     if (cmd[0] == '-')
  71.         cmd++;
  72.     else
  73.     {
  74.         clear_bot();
  75.         putstr("!");
  76.         putstr(cmd);
  77.         putstr("\n");
  78.     }
  79.  
  80.     /*
  81.      * Close the current input file.
  82.      */
  83.     save_ifile = curr_ifile;
  84.     (void) edit_ifile(NULL_IFILE);
  85.  
  86.     /*
  87.      * De-initialize the terminal and take out of raw mode.
  88.      */
  89.     deinit();
  90.     flush();    /* Make sure the deinit chars get out */
  91.     raw_mode(0);
  92.  
  93.     /*
  94.      * Restore signals to their defaults.
  95.      */
  96.     init_signals(0);
  97.  
  98.     /*
  99.      * Force standard input to be the user's terminal
  100.      * (the normal standard input), even if less's standard input 
  101.      * is coming from a pipe.
  102.      */
  103. #if MSOFTC
  104.     inp = dup(0);
  105.     inp2 = open("CON", O_TEXT|O_RDONLY);
  106.     dup2(0,inp2);
  107. #else
  108.     inp = dup(0);
  109.     close(0);
  110.     if (open("/dev/tty", 0) < 0)
  111.         dup(inp);
  112. #endif
  113.  
  114.     /*
  115.      * Pass the command to the system to be executed.
  116.      * If we have a SHELL environment variable, use
  117.      * <$SHELL -c "command"> instead of just <command>.
  118.      * If the command is empty, just invoke a shell.
  119.      */
  120. #if HAVE_SHELL
  121.     p = NULL;
  122.     if ((shell = getenv("SHELL")) != NULL && *shell != '\0')
  123.     {
  124.         if (*cmd == '\0')
  125.             p = save(shell);
  126.         else
  127.         {
  128.             p = (char *) ecalloc(strlen(shell) + strlen(cmd) + 7, 
  129.                     sizeof(char));
  130.             sprintf(p, "%s -c \"%s\"", shell, cmd);
  131.         }
  132.     }
  133.     if (p == NULL)
  134.     {
  135.         if (*cmd == '\0')
  136.             p = save("sh");
  137.         else
  138.             p = save(cmd);
  139.     }
  140.  
  141.     system(p);
  142.     free(p);
  143. #else
  144.     system(cmd);
  145. #endif
  146.  
  147.     /*
  148.      * Restore standard input, reset signals, raw mode, etc.
  149.      */
  150. #if MSOFTC
  151.     close(inp2);
  152.     dup2(0,inp);
  153.     close(inp);
  154. #else
  155.     close(0);
  156.     dup(inp);
  157.     close(inp);
  158. #endif
  159.  
  160.     init_signals(1);
  161.     raw_mode(1);
  162.     init();
  163.     screen_trashed = 1;
  164.  
  165.     /*
  166.      * Reopen the current input file.
  167.      */
  168.     if (edit_ifile(save_ifile))
  169.         quit(-1);
  170.  
  171. #if defined(SIGWINCH) || defined(SIGWIND)
  172.     /*
  173.      * Since we were ignoring window change signals while we executed
  174.      * the system command, we must assume the window changed.
  175.      * Warning: this leaves a signal pending (in "sigs"),
  176.      * so psignals() should be called soon after lsystem().
  177.      */
  178.     winch(0);
  179. #endif
  180. }
  181.  
  182. #endif
  183.  
  184. #if PIPEC
  185.  
  186. /*
  187.  * Pipe a section of the input file into the given shell command.
  188.  * The section to be piped is the section "between" the current
  189.  * position and the position marked by the given letter.
  190.  *
  191.  * The "current" position means the top line displayed if the mark
  192.  * is after the current screen, or the bottom line displayed if
  193.  * the mark is before the current screen.
  194.  * If the mark is on the current screen, the whole screen is displayed.
  195.  */
  196.     public int
  197. pipe_mark(c, cmd)
  198.     int c;
  199.     char *cmd;
  200. {
  201.     POSITION mpos, tpos, bpos;
  202.  
  203.     /*
  204.      * mpos = the marked position.
  205.      * tpos = top of screen.
  206.      * bpos = bottom of screen.
  207.      */
  208.     mpos = markpos(c);
  209.     if (mpos == NULL_POSITION)
  210.         return (-1);
  211.     tpos = position(TOP);
  212.     if (tpos == NULL_POSITION)
  213.         tpos = ch_zero();
  214.     bpos = position(BOTTOM);
  215.  
  216.      if (c == '.') 
  217.          return (pipe_data(cmd, tpos, bpos));
  218.      else if (mpos <= tpos)
  219.          return (pipe_data(cmd, mpos, tpos));
  220.      else if (bpos == NULL_POSITION)
  221.          return (pipe_data(cmd, tpos, bpos));
  222.      else
  223.          return (pipe_data(cmd, tpos, mpos));
  224. }
  225.  
  226. /*
  227.  * Create a pipe to the given shell command.
  228.  * Feed it the file contents between the positions spos and epos.
  229.  */
  230.     public int
  231. pipe_data(cmd, spos, epos)
  232.     char *cmd;
  233.     POSITION spos;
  234.     POSITION epos;
  235. {
  236.     register FILE *f;
  237.     register int c;
  238.     extern FILE *popen();
  239.  
  240.     /*
  241.      * This is structured much like lsystem().
  242.      * Since we're running a shell program, we must be careful
  243.      * to perform the necessary deinitialization before running
  244.      * the command, and reinitialization after it.
  245.      */
  246.     if (ch_seek(spos) != 0)
  247.     {
  248.         error("Cannot seek to start position", NULL_PARG);
  249.         return (-1);
  250.     }
  251.  
  252.     if ((f = popen(cmd, "w")) == NULL)
  253.     {
  254.         error("Cannot create pipe", NULL_PARG);
  255.         return (-1);
  256.     }
  257.     clear_bot();
  258.     putstr("!");
  259.     putstr(cmd);
  260.     putstr("\n");
  261.  
  262.     deinit();
  263.     flush();
  264.     raw_mode(0);
  265.     init_signals(0);
  266. #ifdef SIGPIPE
  267.     SIGNAL(SIGPIPE, SIG_IGN);
  268. #endif
  269.  
  270.     c = EOI;
  271.     while (epos == NULL_POSITION || spos++ <= epos)
  272.     {
  273.         /*
  274.          * Read a character from the file and give it to the pipe.
  275.          */
  276.         c = ch_forw_get();
  277.         if (c == EOI)
  278.             break;
  279.         if (putc(c, f) == EOF)
  280.             break;
  281.     }
  282.  
  283.     /*
  284.      * Finish up the last line.
  285.      */
  286.      while (c != '\n' && c != EOI ) 
  287.      {
  288.          c = ch_forw_get();
  289.          if (c == EOI)
  290.              break;
  291.          if (putc(c, f) == EOF)
  292.              break;
  293.      }
  294.  
  295.     pclose(f);
  296.  
  297. #ifdef SIGPIPE
  298.     SIGNAL(SIGPIPE, SIG_DFL);
  299. #endif
  300.     init_signals(1);
  301.     raw_mode(1);
  302.     init();
  303.     screen_trashed = 1;
  304. #if defined(SIGWINCH) || defined(SIGWIND)
  305.     /* {{ Probably don't need this here. }} */
  306.     winch(0);
  307. #endif
  308.     return (0);
  309. }
  310.  
  311. #endif
  312.